/* 网格图模型

* 本题:
    对于某个点 (x,y) 来说，其分别向 (x+1,y) 和 (x,y+1) 连边，容量为 1，费用为边权，
    同理，由于边权只能取一次，所以其还需再分别向 (x+1,y) 和 (x,y+1) 连一条容量足够大，费用为 0 的边，
    建立源点 s 和汇点 t，s 向出发的位置连边，容量为其上的机器人数量，费用为 0，
    所有目的位置向 t 连边，容量为该位置可容纳机器人的数量，费用为 0，
    求解从 s 到 t 的最大费用最大流即为所求

    从 s 出发到某个出发位置的可行流可以看成从该位置出发的机器人数量，
    且如果其经过某个边容量为 1 的边，下一次其他可行流就不会经过该边，即每个边权只能取一次，
    最大流->出发的机器人尽可能多

*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5010, M = N*8, INF=0x3f3f3f3f;
int n, m, P, Q, S, T;
int h[N], e[M], c[M], w[M], ne[M], idx;
int q[N], pre[N], incf[N], d[N];
bool st[N];

#define get(x,y) ((x)*(m+1)+y)

void AddEdge(int a, int b, int cc, int ww)
{
    e[idx]=b, c[idx]=cc, w[idx]=ww, ne[idx]=h[a], h[a]=idx++;
    e[idx]=a, c[idx]=0, w[idx]=-ww, ne[idx]=h[b], h[b]=idx++;
}

bool spfa()
{
    memset(d, -0x3f, sizeof d);
    memset(incf, 0, sizeof incf);
    int hh=0, tt=0;
    q[tt++]=S, d[S]=0, incf[S]=INF;
    while(hh!=tt)
    {
        int u=q[hh++];
        if(hh==N) hh=0;
        st[u]=false;
        for(int i=h[u]; ~i; i=ne[i])
        {
            int v=e[i];
            if(c[i] && d[v]<d[u]+w[i])
            {
                d[v]=d[u]+w[i];
                pre[v]=i;
                incf[v]=min(incf[u], c[i]);
                if(!st[v])
                {
                    q[tt++]=v;
                    if(tt==N) tt=0;
                    st[v]=true;
                }
            }
        }
    }
    return incf[T]>0;
}

int EK()
{
    int cost = 0;
    while(spfa())
    {
        cost += incf[T]*d[T];
        for(int i=T; i!=S; i=e[pre[i]^1])
        {
            c[pre[i]]-=incf[T]; c[pre[i]^1]+=incf[T];
        }
    }
    return cost;
}


signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    #endif

    memset(h, -1, sizeof h);

    cin >> P >> Q >> n >> m;
    S=(n+1)*(m+1), T=S+1; 

    for(int i=0; i<=n; i++)
        for(int j=0; j<m; j++)
        {
            int c; cin >> c;
            AddEdge(get(i,j), get(i,j+1), 1, c); //向右走 取当前点
            AddEdge(get(i,j), get(i,j+1), INF, 0); //向右走 不取当前点
        }

    for(int j=0; j<=m; j++)        
        for(int i=0; i<n; i++)       
        {
            int c; cin >> c;
            AddEdge(get(i,j), get(i+1,j), 1, c); //向下走 取当前点
            AddEdge(get(i,j), get(i+1,j), INF, 0); //向下走 不取当前点
        }

    int k, x, y;
    while(P--) //直接以任意可取点为起点
    {
        cin >> k >> x >> y;
        AddEdge(S, get(x, y), k, 0);
    }
    while(Q--) //直接以任意可取点为终点
    {
        cin >> k >> x >> y;
        AddEdge(get(x, y), T, k, 0);
    }
    printf("%d\n", EK());
    return 0;
}